package
{
	
	/**
	*  The Struct class implements an ArrayCollection class with an easy way
	 * to lookup up keys.
	*/	
	import flash.utils.flash_proxy;
	
	import mx.collections.ArrayCollection;
	import mx.events.CollectionEvent;
	
	import smashedapples.events.StructEvent;
	
	use namespace flash_proxy;
	
	[Event(name="add",type="smashedapples.events.StructEvent")]
	[Event(name="move",type="smashedapples.events.StructEvent")]
	[Event(name="refresh",type="smashedapples.events.StructEvent")]
	[Event(name="replace",type="smashedapples.events.StructEvent")]
	[Event(name="update",type="smashedapples.events.StructEvent")]
	
	public class Struct extends ArrayCollection
	{
		public function Struct( source:Array=null )
		{
			super(source);
			this.addEventListener(CollectionEvent.COLLECTION_CHANGE, collectionChangeHandler );
		}
		
		private function collectionChangeHandler(event:CollectionEvent):void
		{	
			dispatchEvent( new StructEvent( event.kind, event.location, event.oldLocation, event.items ));
		}
		
		
		private var _keyIndex:Object = new Object();
		
		/**
		 * 
		 * @return Object
		 * 
		 */		
		public function get keyIndex():Object
    	{
        	return _keyIndex;
    	}
		
   		/**
   		 * 
   		 * @param value
   		 * 
   		 */   		
   		public function set keyIndex(value:Object):void
    	{
        	_keyIndex = value;
    	}
		
		
		[Bindable("hasKeyChanged")]
		/**
		 * 
		 * @param key Key to lookup
		 * @return true if key exists in the keyIndex else false
		 * 
		 */		
		public function hasKey(key:String):Boolean
		{
			if(this.keyIndex[key] == null)
				return false;		
			return true;
		}
		
		
		public function deleteByKey( key:String ):void
		{
			if( this.hasKey( key ))
			{
				//delete this[ key ];
			}
		}
		
		
		[Bindable("collectionChange")]
		/**
		 * 
		 * @param key 
		 * @param value
		 * 
		 */		
		public function addByKey(key:Object,value:Object):void 
		{
			var index:* = keyIndex[key];
			if (index == null) 
			{
				index = this.length;
				this.addItem(value);
				keyIndex[key] = index;
				this.setItemAt(value,index as int);
			} 
			else 
			{
				this.setItemAt(value,index as int);
			}
		}			
		
		[Bindable("collectionChange")]
		/**
		 * 
		 * @param key
		 * @return 
		 * 
		 */		
		public function getByKey(key:Object):Object 
		{
			var index:* = keyIndex[key];

			if (index == undefined) 
				return null

			return super.getItemAt( index as int);
		}
		
		
		/**
		 *  Override of flash_proxy getProperty() to do a lookup on the property. 
		 *  If the property does not exists in the Struct Class it assumes the property is
		 *  key on the array. For example, Struct extends ArrayCollection so you can access the
		 *  length field as myStruct.length or myStruct["length"].
		 *  
		 *  Any property name accessed with brackets that does not exist on the Struct Class, will be looked for in the key index.
		 *  myStruct["123"] will look for a value where the key = 123.
		 * 
		 * @param name
		 * @return 
		 * 
		 */		
		override flash_proxy function getProperty(name:*):*
    	{	
    		
    		if(this.hasOwnProperty(name))
    		{
    			return super.getProperty(name);
    		}
    		
    		return getByKey(name);
    	}
    	
		/**
		 *  
		 * @param name
		 * @param value
		 * 
		 */    	
		override flash_proxy function setProperty(name:*, value:*):void
    	{
    		if(this.hasOwnProperty(name))
    		{
    			super.setProperty(name,value);
    		}
    		else
    		{
    			addByKey(name,value);
    		}	
    	} 
    	
    	
    	
		
	}
}